home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / editors / mjovesrc.zoo / c.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-04  |  16.7 KB  |  752 lines

  1. /***************************************************************************
  2.  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  3.  * is provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is    *
  5.  * included in all the files.                                              *
  6.  ***************************************************************************/
  7.  
  8. /* Contains commands for C mode.  Paren matching routines are in here. */
  9.  
  10. #include "jove.h"
  11. #include "re.h"
  12. #include "ctype.h"
  13. #include "disp.h"
  14.  
  15. private void
  16. #ifdef    CMT_FMT
  17.     FillComment proto((char *format)),
  18. #endif
  19.     FindMatch proto((int));
  20.  
  21. private int
  22. backslashed(lp, cpos)
  23. register char    *lp;
  24. register int    cpos;
  25. {
  26.     register int    cnt = 0;
  27.  
  28.     while (cpos > 0 && lp[--cpos] == '\\')
  29.         cnt += 1;
  30.     return (cnt % 2);
  31. }
  32.  
  33. private char    *p_types = "(){}[]";
  34. private int    mp_kind;
  35. #define MP_OKAY        0
  36. #define MP_MISMATCH    1
  37. #define MP_UNBALANCED    2
  38. #define MP_INCOMMENT    3
  39.  
  40. void
  41. mp_error()
  42. {
  43.     switch (mp_kind) {
  44.     case MP_MISMATCH:
  45.         message("[Mismatched parentheses]");
  46.         break;
  47.  
  48.     case MP_UNBALANCED:
  49.         message("[Unbalanced parenthesis]");
  50.         break;
  51.  
  52.     case MP_INCOMMENT:
  53.         message("[Inside a comment]");
  54.         break;
  55.  
  56.     case MP_OKAY:
  57.     default:
  58.         return;
  59.     }
  60.     rbell();
  61. }
  62.  
  63. /* Search from the current position for the paren that matches p_type.
  64.    Search in the direction dir.  If can_mismatch is YES then it is okay
  65.    to have mismatched parens.  If stop_early is YES then when an open
  66.    paren is found at the beginning of a line, it is assumed that there
  67.    is no point in backing up further.  This is so when you hit tab or
  68.    LineFeed outside, in-between procedure/function definitions, it won't
  69.    sit there searching all the way to the beginning of the file for a
  70.    match that doesn't exist.  {forward,backward}-s-expression are the
  71.    only ones that insist on getting the "true" story. */
  72.  
  73. Bufpos *
  74. m_paren(p_type, dir, can_mismatch, can_stop)
  75. int    p_type;
  76. register int    dir;
  77. int    can_mismatch;
  78. int    can_stop;
  79. {
  80.     static Bufpos    ret;
  81.     Bufpos    savedot,
  82.         *sp;
  83.     struct RE_block    re_blk;
  84.     int    count = 0;
  85.     register char    *lp,
  86.             c;
  87.     char    p_match,
  88.         re_str[128],
  89.         *cp,
  90.         quote_c = 0;
  91.     register int    c_char;
  92.     int    in_comment = -1,
  93.         stopped = NO;
  94.  
  95.     swritef(re_str, sizeof(re_str), "[(){}[\\]%s]",
  96.         (MajorMode(CMODE)) ? "/\"'" : "\"");
  97.     REcompile(re_str, YES, &re_blk);
  98.     if ((cp = strchr(p_types, p_type)) == NULL)
  99.         complain("[Cannot match %c's]", p_type);
  100.     p_match = cp[dir];
  101.     DOTsave(&savedot);
  102.  
  103.     /* To make things a little faster I avoid copying lines into
  104.        linebuf by setting curline and curchar by hand.  Warning:
  105.        this is slightly to very risky.  When I did this there were
  106.        lots of problems with procedures that expect the contents of
  107.        curline to be in linebuf. */
  108.     do {
  109.         sp = docompiled(dir, &re_blk);
  110.         if (sp == NULL)
  111.             break;
  112.         lp = lbptr(sp->p_line);
  113.  
  114.         curline = sp->p_line;
  115.         curchar = sp->p_char;    /* here's where I cheat */
  116.  
  117.         c_char = curchar;
  118.         if (dir == FORWARD)
  119.             c_char -= 1;
  120.         if (backslashed(lp, c_char))
  121.             continue;
  122.         c = lp[c_char];
  123.         /* check if this is a comment (if we're not inside quotes) */
  124.         if (quote_c == 0 && c == '/') {
  125.             int    new_ic = in_comment;
  126.  
  127.             /* close comment */
  128.             if ((c_char != 0) && lp[c_char - 1] == '*') {
  129.                 new_ic = (dir == FORWARD) ? NO : YES;
  130.                 if (new_ic == NO && in_comment == -1) {
  131.                     count = 0;
  132.                     quote_c = 0;
  133.                 }
  134.             } else if (lp[c_char + 1] == '*') {
  135.                 new_ic = (dir == FORWARD) ? YES : NO;
  136.                 if (new_ic == NO && in_comment == -1) {
  137.                     count = 0;
  138.                     quote_c = 0;
  139.                 }
  140.             }
  141.             in_comment = new_ic;
  142.         }
  143.         if (in_comment == YES)
  144.             continue;
  145.         if (c == '"' || c == '\'') {
  146.             if (quote_c == c)
  147.                 quote_c = 0;
  148.             else if (quote_c == 0)
  149.                 quote_c = c;
  150.         }
  151.         if (quote_c != 0)
  152.             continue;
  153.         if (jisopenp(c)) {
  154.             count += dir;
  155.             if (c_char == 0 && can_stop == YES && count >= 0) {
  156.                 stopped = YES;
  157.                 break;
  158.             }
  159.         } else if (jisclosep(c))
  160.             count -= dir;
  161.     } while (count >= 0);
  162.  
  163.     ret.p_line = curline;
  164.     ret.p_char = curchar;
  165.  
  166.     curline = savedot.p_line;
  167.     curchar = savedot.p_char;    /* here's where I undo it */
  168.  
  169.     if (count >= 0)
  170.         mp_kind = MP_UNBALANCED;
  171.     else if (c != p_match)
  172.         mp_kind = MP_MISMATCH;
  173.     else
  174.         mp_kind = MP_OKAY;
  175.  
  176.     /* If we stopped (which means we were allowed to stop) and there
  177.        was an error, we clear the error so no error message is printed.
  178.        An error should be printed ONLY when we are sure about the fact,
  179.        namely we didn't stop prematurely HOPING that it was the right
  180.        answer. */
  181.     if (stopped && mp_kind != MP_OKAY) {
  182.         mp_kind = MP_OKAY;
  183.         return NULL;
  184.     }
  185.     if (mp_kind == MP_OKAY || (mp_kind == MP_MISMATCH && can_mismatch == YES))
  186.         return &ret;
  187.     return NULL;
  188. }
  189.  
  190. private void
  191. do_expr(dir, skip_words)
  192. register int    dir;
  193. int    skip_words;
  194. {
  195.     register char    c,
  196.             syntax = (dir == FORWARD) ? C_BRA : C_KET;
  197.  
  198.     if (dir == BACKWARD)
  199.         b_char(1);
  200.     c = linebuf[curchar];
  201.     for (;;) {
  202.         if (!skip_words && ismword(c)) {
  203.             WITH_TABLE(curbuf->b_major)
  204.             if (dir == FORWARD)
  205.                 f_word(1);
  206.             else
  207.                 b_word(1);
  208.             END_TABLE();
  209.             break;
  210.         } else if (has_syntax(c, syntax)) {
  211.             FindMatch(dir);
  212.             break;
  213.         }
  214.         f_char(dir);
  215.         if (eobp() || bobp())
  216.             return;
  217.         c = linebuf[curchar];
  218.     }
  219. }
  220.  
  221. void
  222. FSexpr()
  223. {
  224.     register int    num = arg_value();
  225.  
  226.     if (num < 0) {
  227.         set_arg_value(-num);
  228.         BSexpr();
  229.     }
  230.     while (--num >= 0)
  231.         do_expr(FORWARD, NO);
  232. }
  233.  
  234. void
  235. FList()
  236. {
  237.     register int    num = arg_value();
  238.  
  239.     if (num < 0) {
  240.         set_arg_value(-num);
  241.         BList();
  242.     }
  243.     while (--num >= 0)
  244.         do_expr(FORWARD, YES);
  245. }
  246.  
  247. void
  248. BSexpr()
  249. {
  250.     register int    num = arg_value();
  251.  
  252.     if (num < 0) {
  253.         negate_arg_value();
  254.         FSexpr();
  255.     }
  256.     while (--num >= 0)
  257.         do_expr(BACKWARD, NO);
  258. }
  259.  
  260. void
  261. BList()
  262. {
  263.     register int    num = arg_value();
  264.  
  265.     if (num < 0) {
  266.         negate_arg_value();
  267.         FList();
  268.     }
  269.     while (--num >= 0)
  270.         do_expr(BACKWARD, YES);
  271. }
  272.  
  273. void
  274. BUpList()
  275. {
  276.     Bufpos    *mp;
  277.     char    c = (MajorMode(CMODE) ? '}' : ')');
  278.  
  279.     mp = m_paren(c, BACKWARD, NO, YES);
  280.     if (mp == NULL)
  281.         mp_error();
  282.     else
  283.         SetDot(mp);
  284. }
  285.  
  286. void
  287. FDownList()
  288. {
  289.     Bufpos    *sp;
  290.     char    *sstr = MajorMode(CMODE) ? "[{([\\])}]" : "[()]";
  291.  
  292.     sp = dosearch(sstr, FORWARD, YES);
  293.     if (sp == NULL || has_syntax(lcontents(sp->p_line)[sp->p_char - 1], C_KET))
  294.         complain("[No contained expression]");
  295.     SetDot(sp);
  296. }
  297.  
  298. /* Move to the matching brace or paren depending on the current position
  299.    in the buffer. */
  300.  
  301. private void
  302. FindMatch(dir)
  303. int    dir;
  304. {
  305.     register Bufpos    *bp;
  306.     register char    c = linebuf[curchar];
  307.  
  308.     if ((strchr(p_types, c) == NULL) ||
  309.         (backslashed(linebuf, curchar)))
  310.         complain((char *)NULL);
  311.     if (dir == FORWARD)
  312.         f_char(1);
  313.     bp = m_paren(c, dir, YES, NO);
  314.     if (dir == FORWARD)
  315.         b_char(1);
  316.     if (bp != NULL)
  317.         SetDot(bp);
  318.     mp_error();    /* if there is an error the user wants to
  319.                know about it */
  320. }
  321.  
  322. #define ALIGN_ARGS    (-1)
  323.  
  324. /* If CArgIndent == ALIGN_ARGS then the indentation routine will
  325.    indent a continued line by lining it up with the first argument.
  326.    Otherwise, it will indent CArgIndent characters past the indent
  327.    of the first line of the procedure call. */
  328.  
  329. int    CArgIndent = ALIGN_ARGS;
  330.  
  331. /* indent for C code */
  332. Bufpos *
  333. c_indent(brace)
  334. int    brace;
  335. {
  336.     Bufpos    *bp;
  337.     int    new_indent = 0,
  338.         current_indent,
  339.         increment;
  340.  
  341.     if (brace == NO)
  342.         increment = CIndIncrmt;
  343.     else
  344.         increment = 0;
  345.     /* Find matching paren, which may be a mismatch now.  If it
  346.        is not a matching curly brace then it is a paren (most likely).
  347.        In that case we try to line up the arguments to a procedure
  348.        or inside an of statement. */
  349.     if ((bp = m_paren('}', BACKWARD, YES, YES)) != NULL) {
  350.         Bufpos    save;
  351.         int    matching_indent;
  352.  
  353.         DOTsave(&save);
  354.         SetDot(bp);        /* go to matching paren */
  355.         ToIndent();
  356.         matching_indent = calc_pos(linebuf, curchar);
  357.         SetDot(bp);
  358.         switch (linebuf[curchar]) {
  359.         case '{':
  360.             new_indent = matching_indent;
  361.             if (!bolp()) {
  362.                 b_char(1);
  363.                 /* If we're not within the indent then we
  364.                    can assume that there is either a C keyword
  365.                    line DO on the line before the brace, or
  366.                    there is a parenthesized expression.  If
  367.                    that's the case we want to go backward
  368.                    over that to the beginning of the expression
  369.                    so that we can get the correct indent for
  370.                    this matching brace.  This handles wrapped
  371.                    if statements, etc. */
  372.                 if (!within_indent()) {
  373.                     Bufpos    savematch;
  374.  
  375.                     savematch = *bp;
  376.  
  377.                     do_expr(BACKWARD, NO);
  378.                     ToIndent();
  379.                     new_indent = calc_pos(linebuf, curchar);
  380.  
  381.                     /* do_expr() calls b_paren, which
  382.                        returns a pointer to a structure,
  383.                        and that pointer is in BP so we
  384.                        have to save away the matching
  385.                        paren and restore it in the
  386.                        following line ... sigh */
  387.                     *bp = savematch;
  388.                 }
  389.             }
  390.             if (brace == NO)
  391.                 new_indent += (increment - (new_indent % increment));
  392.             break;
  393.  
  394.         case '(':
  395.             if (CArgIndent == ALIGN_ARGS) {
  396.                 f_char(1);
  397.                 new_indent = calc_pos(linebuf, curchar);
  398.             } else
  399.                 new_indent = matching_indent + CArgIndent;
  400.             break;
  401.         }
  402.         SetDot(&save);
  403.     }
  404.  
  405.     /* new_indent is the "correct" place to indent.  Now we check to
  406.        see if what we consider as the correct place to indent is to
  407.        the LEFT of where we already are.  If it is, and we are NOT
  408.        handling a brace, then we assume that the person wants to tab
  409.        in further than what we think is right (for some reason) and
  410.        so we allow that. */
  411.  
  412.     ToIndent();
  413.     current_indent = calc_pos(linebuf, curchar);
  414.     if (brace == NO && new_indent <= current_indent)
  415.         new_indent = current_indent + (increment - (current_indent % increment));
  416.     Bol();
  417.     DelWtSpace();            /* nice uniform Tabs*Space* */
  418.     n_indent(new_indent);
  419.  
  420.     return bp;
  421. }
  422.  
  423. private void
  424. re_indent(incr)
  425. int    incr;
  426. {
  427.     Line    *l1, *l2, *lp;
  428.     int    c1, c2;
  429.     Mark    *m = CurMark();
  430.     Bufpos    savedot;
  431.  
  432.     DOTsave(&savedot);
  433.     l1 = curline;
  434.     c1 = curchar;
  435.     l2 = m->m_line;
  436.     c2 = m->m_char;
  437.     (void) fixorder(&l1, &c1, &l2, &c2);
  438.     for (lp = l1; lp != l2->l_next; lp = lp->l_next) {
  439.         int    indent;
  440.  
  441.         SetLine(lp);
  442.         ToIndent();
  443.         indent = calc_pos(linebuf, curchar);
  444.         if (indent != 0 || linebuf[0] != '\0')
  445.             n_indent(indent + incr);
  446.     }
  447.     SetDot(&savedot);
  448. }
  449.  
  450. void
  451. LRShift()
  452. {
  453.     int    amnt;
  454.  
  455.     if (is_an_arg())
  456.         amnt = arg_value();
  457.     else
  458.         amnt = CIndIncrmt;
  459.     re_indent(-amnt);
  460. }
  461.  
  462. void
  463. RRShift()
  464. {
  465.     int    amnt;
  466.  
  467.     if (is_an_arg())
  468.         amnt = arg_value();
  469.     else
  470.         amnt = CIndIncrmt;
  471.     re_indent(amnt);
  472. }
  473.  
  474. #ifdef    CMT_FMT
  475.  
  476. char    CmtFmt[80] = "/*%n%! * %c%!%n */";
  477.  
  478. void
  479. Comment()
  480. {
  481.     FillComment(CmtFmt);
  482. }
  483.  
  484. /* Strip leading and trailing white space.  Skip over any imbedded '\r's. */
  485.  
  486. private void
  487. strip_c(from, to)
  488. char    *from,
  489.     *to;
  490. {
  491.     register char    *fr_p = from,
  492.             *to_p = to,
  493.             c;
  494.  
  495.     while ((c = *fr_p) != '\0') {
  496.         if (c == ' ' || c == '\t' || c == '\r')
  497.             fr_p += 1;
  498.         else
  499.             break;
  500.     }
  501.     while ((c = *fr_p) != '\0') {
  502.         if (c != '\r')
  503.             *to_p++ = c;
  504.         fr_p += 1;
  505.     }
  506.     while (--to_p >= to)
  507.         if (*to_p != ' ' && *to_p != '\t')
  508.             break;
  509.     *++to_p = '\0';
  510. }
  511.  
  512. private char    open_c[20],    /* the open comment format string */
  513.         open_pat[20],    /* the search pattern for open comment */
  514.         l_header[20],    /* the prefix for each comment line */
  515.         l_trailer[20],    /* the suffix ... */
  516.         close_c[20],
  517.         close_pat[20];
  518.  
  519. private char    *const comment_body[] = {
  520.     open_c,
  521.     l_header,
  522.     l_trailer,
  523.     close_c
  524. };
  525.  
  526. private int    nlflags;
  527.  
  528. /* Fill in the data structures above from the format string.  Don't return
  529.    if there's trouble. */
  530.  
  531. private void
  532. parse_cmt_fmt(str)
  533. char    *str;
  534. {
  535.     register char    *fmtp = str;
  536.     register char    *const *c_body = comment_body,
  537.             *body_p = *c_body;
  538.     int    c,
  539.         newlines = 1;
  540.  
  541.     /* pick apart the comment string */
  542.     while ((c = *fmtp++) != '\0') {
  543.         if (c != '%') {
  544.             *body_p++ = c;
  545.             continue;
  546.         }
  547.         switch(c = *fmtp++) {
  548.         case 'n':
  549.             if (newlines == 2 || newlines == 3)
  550.                 complain("%n not allowed in line header or trailer: %s",
  551.                   fmtp - 2);
  552.             nlflags += newlines;
  553.             *body_p++ = '\r';
  554.             break;
  555.         case 't':
  556.             *body_p++ = '\t';
  557.             break;
  558.         case '%':
  559.             *body_p++ = '%';
  560.             break;
  561.         case '!':
  562.         case 'c':
  563.             newlines += 1;
  564.             *body_p++ = '\0';
  565.             body_p = *++c_body;
  566.             break;
  567.         default:
  568.             complain("[Unknown comment escape: %%%c]", c);
  569.             break;
  570.         }
  571.     }
  572.     *body_p = '\0';
  573.     /* make search patterns */
  574.     strip_c(open_c, open_pat);
  575.     strip_c(close_c, close_pat);
  576. }
  577.  
  578. #define NL_IN_OPEN_C  ((nlflags % 4) == 1)
  579. #define NL_IN_CLOSE_C (nlflags >= 4)
  580.  
  581. private void
  582. FillComment(format)
  583. char    *format;
  584. {
  585.     int    saveRMargin,
  586.         indent_pos;
  587.     bool    close_at_dot = NO;
  588.     size_t    header_len,
  589.         trailer_len;
  590.     register char    *cp;
  591.     static const char    inside_err[] = "[Must be between %s and %s to re-format]";
  592.     Bufpos    open_c_pt,
  593.         close_c_pt,
  594.         tmp_bp,
  595.         *match_o,
  596.         *match_c;
  597.     Mark    *entry_mark,
  598.         *open_c_mark,
  599.         *savedot;
  600.  
  601.     parse_cmt_fmt(format);
  602.     /* figure out if we're "inside" a comment */
  603.     if ((match_o = dosearch(open_pat, BACKWARD, NO)) == NULL)
  604.         complain("No opening %s to match to.", open_pat);
  605.     open_c_pt = *match_o;
  606.     if ((match_c = dosearch(close_pat, BACKWARD, NO)) != NULL &&
  607.         inorder(open_c_pt.p_line, open_c_pt.p_char,
  608.             match_c->p_line, match_c->p_char))
  609.         complain(inside_err, open_pat, close_pat);
  610.     if ((match_o = dosearch(open_pat, FORWARD, NO)) != NULL) {
  611.         tmp_bp = *match_o;
  612.         match_o = &tmp_bp;
  613.     }
  614.     if ((match_c = dosearch(close_pat, FORWARD, NO)) != NULL)
  615.         close_c_pt = *match_c;
  616.  
  617.     /* Here's where we figure out whether to format from dot or from
  618.        the close comment.  Note that we've already searched backwards to
  619.        find the open comment symbol for the comment we are formatting.
  620.        The open symbol mentioned below refers to the possible existence
  621.        of the next comment.  There are 5 cases:
  622.         1) no open or close symbol        ==> dot
  623.         2) open, but no close symbol        ==> dot
  624.         3) close, but no open            ==> close
  625.         4) open, close are inorder        ==> dot
  626.         5) open, close are not inorder        ==> close */
  627.  
  628.  
  629.     if (match_o == (Bufpos *)NULL) {
  630.         if (match_c == (Bufpos *)NULL)
  631.             close_at_dot = YES;
  632.     } else if (match_c == (Bufpos *)NULL)
  633.         close_at_dot = YES;
  634.     else if (inorder(match_o->p_line, match_o->p_char,
  635.          match_c->p_line, match_c->p_char))
  636.         close_at_dot = YES;
  637.     if (close_at_dot) {
  638.         close_c_pt.p_line = curline;
  639.         close_c_pt.p_char = curchar;
  640.     } else {
  641.         SetDot(match_c);
  642.     }
  643.     SetDot(&open_c_pt);
  644.     open_c_mark = MakeMark(curline, curchar, M_FLOATER);
  645.     indent_pos = calc_pos(linebuf, curchar);
  646.     /* search for a close comment; delete it if it exits */
  647.     SetDot(&close_c_pt);
  648.     if (!close_at_dot)
  649.         del_char(BACKWARD, (int)strlen(close_pat), NO);
  650.     entry_mark = MakeMark(curline, curchar, M_FLOATER);
  651.     ToMark(open_c_mark);
  652.     /* always separate the comment body from anything preceeding it */
  653.     LineInsert(1);
  654.     DelWtSpace();
  655.     Bol();
  656.     for (cp = open_c; *cp; cp++) {
  657.         if (*cp == '\r') {
  658.             if (!eolp())
  659.                 LineInsert(1);
  660.             else
  661.                 line_move(FORWARD, 1, NO);
  662.         } else if (*cp == ' ' || *cp == '\t') {
  663.             if (linebuf[curchar] != *cp)
  664.                 insert_c(*cp, 1);
  665.         } else {
  666.             /* Since we matched the open comment string on this
  667.                line, we don't need to worry about crossing line
  668.                boundaries. */
  669.             curchar += 1;
  670.         }
  671.     }
  672.     savedot = MakeMark(curline, curchar, M_FLOATER);
  673.  
  674.     /* We need to strip the line header pattern of leading white space
  675.        since we need to match the line after all of its leading
  676.        whitespace is gone. */
  677.     for (cp = l_header; *cp && (jisspace(*cp)); cp++)
  678.         ;
  679.     header_len = strlen(cp);
  680.     trailer_len = strlen(l_trailer);
  681.  
  682.     /* Strip each comment line of the open and close comment strings
  683.        before reformatting it. */
  684.  
  685.     do {
  686.         Bol();
  687.         DelWtSpace();
  688.         if (header_len && strncmp(linebuf, cp, header_len)==0)
  689.             del_char(FORWARD, (int)header_len, NO);
  690.         if (trailer_len) {
  691.             Eol();
  692.             if (((size_t)curchar > trailer_len) &&
  693.                 (strncmp(&linebuf[curchar - trailer_len],
  694.                       l_trailer, trailer_len)==0))
  695.                 del_char(BACKWARD, (int)trailer_len, NO);
  696.         }
  697.         if (curline->l_next != NULL)
  698.             line_move(FORWARD, 1, NO);
  699.         else
  700.             break;
  701.     } while (curline != entry_mark->m_line->l_next);
  702.  
  703.     do_set_mark(savedot->m_line, savedot->m_char);
  704.     ToMark(entry_mark);
  705.     saveRMargin = RMargin;
  706.     RMargin = saveRMargin - strlen(l_header) -
  707.           strlen(l_trailer) - indent_pos + 2;
  708.     do_rfill(NO);
  709.     RMargin = saveRMargin;
  710.     /* get back to the start of the comment */
  711.     PopMark();
  712.     do {
  713.         if (curline != open_c_mark->m_line->l_next) {
  714.             Bol();
  715.             n_indent(indent_pos);
  716.             ins_str(l_header, NO);
  717.         }
  718.         Eol();
  719.         if (NL_IN_CLOSE_C || (curline != entry_mark->m_line))
  720.             ins_str(l_trailer, NO);
  721.         if (curline->l_next != NULL)
  722.             line_move(FORWARD, 1, NO);
  723.         else
  724.             break;
  725.     } while (curline != entry_mark->m_line->l_next);
  726.     /* handle the close comment symbol */
  727.     if (curline == entry_mark->m_line->l_next) {
  728.         line_move(BACKWARD, 1, NO);
  729.         Eol();
  730.     }
  731.     DelWtSpace();
  732.     /* if the addition of the close symbol would cause the line to be
  733.        too long, put the close symbol on the next line. */
  734.     if (!(NL_IN_CLOSE_C) &&
  735.       (int)strlen(close_c) + calc_pos(linebuf, curchar) > RMargin) {
  736.         LineInsert(1);
  737.         n_indent(indent_pos);
  738.     }
  739.     for (cp = close_c; *cp; cp++) {
  740.         if (*cp == '\r') {
  741.             LineInsert(1);
  742.             n_indent(indent_pos);
  743.         } else
  744.             insert_c(*cp, 1);
  745.     }
  746.     ToMark(open_c_mark);
  747.     Eol();
  748.     del_char(FORWARD, 1, NO);
  749. }
  750.  
  751. #endif    /* CMT_FMT */
  752.